#ifndef MDS_OP_TYPE_H
#define MDS_OP_TYPE_H

#include <sstream>
#include <string>
#include <cstring>
#define MAX_PATH_LENGTH 255
#define MAX_NAME_LENGTH 63

using namespace std;



struct Inode;
struct Dir;
struct Dentry;
struct Fileblk;

struct Inode {
	uint64_t	id;
	char			name[MAX_NAME_LENGTH];
	uint64_t	ctime;
	uint64_t	mtime;
	uint64_t	atime;
	uint64_t	mode;
	uint64_t	uid;
	uint64_t	gid;
	uint64_t	size;
	uint64_t	bsize;

	void encode(string *out)
	{
		(*out) += to_string(id);
		(*out) += '\n';
		(*out) += name;
		(*out) += '\n';
		(*out) += to_string(ctime);
		(*out) += '\n';
		(*out) += to_string(mtime);
		(*out) += '\n';
		(*out) += to_string(atime);
		(*out) += '\n';
		(*out) += to_string(mode);
		(*out) += '\n';
		(*out) += to_string(uid);
		(*out) += '\n';
		(*out) += to_string(gid);
		(*out) += '\n';
		(*out) += to_string(size);
		(*out) += '\n';
		(*out) += to_string(bsize);
		(*out) += '\n';
	}
	void decode(string &in)
	{
		istringstream iss(in);
		string token;
		getline(iss, token, '\n');
		id = stoull(token);
		getline(iss, token, '\n');
		strcpy(name, token.c_str());
		getline(iss, token, '\n');
		ctime = stoull(token);
		getline(iss, token, '\n');
		mtime = stoull(token);
		getline(iss, token, '\n');
		atime = stoull(token);
		getline(iss, token, '\n');
		mode = stoull(token);
		getline(iss, token, '\n');
		uid = stoull(token);
		getline(iss, token, '\n');
		gid = stoull(token);
		getline(iss, token, '\n');
		size = stoull(token);
		getline(iss, token, '\n');
		bsize = stoull(token);
	}
};
struct Dir {
	uint64_t	id;
	char			name[MAX_NAME_LENGTH];
	uint64_t	ctime;
	uint64_t	mode;
	uint64_t	uid;
	uint64_t	gid;

	void encode(string *out)
	{
		(*out) += to_string(id);
		(*out) += '\n';
		(*out) += name;
		(*out) += '\n';
		(*out) += to_string(ctime);
		(*out) += '\n';
		(*out) += to_string(mode);
		(*out) += '\n';
		(*out) += to_string(uid);
		(*out) += '\n';
		(*out) += to_string(gid);
		(*out) += '\n';
	}
	void decode(string &in)
	{
		istringstream iss(in);
		string token;
		getline(iss, token, '\n');
		id = stoull(token);
		getline(iss, token, '\n');
		strcpy(name, token.c_str());
		getline(iss, token, '\n');
		ctime = stoull(token);
		getline(iss, token, '\n');
		mode = stoull(token);
		getline(iss, token, '\n');
		uid = stoull(token);
		getline(iss, token, '\n');
		gid = stoull(token);
	}
};
struct Dentry {
	uint64_t	id;
	char			name[MAX_NAME_LENGTH];
	int				type;

	void encode(string *out)
	{
		(*out) += to_string(id);
		(*out) += '\t';
		(*out) += name;
		(*out) += '\t';
		(*out) += to_string(type);
		(*out) += '\t';
	}
	void decode(string &in)
	{
		istringstream iss(in);
		string token;
		getline(iss, token, '\t');
		id = stoull(token);
		getline(iss, token, '\t');
		strcpy(name, token.c_str());
		getline(iss, token, '\t');
		type = stoi(token);
	}
};
struct Fileblk {
	uint64_t	blkno;
	struct chunk_id chunkid;

	void encode(string *out)
	{
		(*out) += to_string(blkno);
		(*out) += '\t';
		(*out) += to_string(chunkid.cs_id);
		(*out) += '\t';
		(*out) += to_string(chunkid.blob_id);
		(*out) += '\t';
	}
	void decode(string &in)
	{
		istringstream iss(in);
		string token;
		getline(iss, token, '\t');
		blkno = stoull(token);
		getline(iss, token, '\t');
		chunkid.cs_id = stoull(token);
		getline(iss, token, '\t');
		chunkid.blob_id = stoull(token);
	}

};


enum {
	MDS_FILE_MKNOD = 0,
	MDS_FILE_MKNOD_REPLY,
	MDS_FILE_MKDIR,
	MDS_FILE_MKDIR_REPLY,
	MDS_FILE_UNLINK,
	MDS_FILE_UNLINK_REPLY,
	MDS_FILE_RMDIR,
	MDS_FILE_RMDIR_REPLY,
	MDS_FILE_RENAME,
	MDS_FILE_RENAME_REPLY,
	MDS_FILE_STAT,
	MDS_FILE_STAT_REPLY,
	MDS_FILE_CHMOD,
	MDS_FILE_CHMOD_REPLY,
	MDS_FILE_CHOWN,
	MDS_FILE_CHOWN_REPLY,
	MDS_FILE_OPEN,
	MDS_FILE_OPEN_REPLY,
	MDS_FILE_READ,
	MDS_FILE_READ_REPLY,
	MDS_FILE_WRITE,
	MDS_FILE_WRITE_REPLY,
	MDS_FILE_TRUNCATE,
	MDS_FILE_TRUNCATE_REPLY,
	MDS_FILE_CLOSE,
	MDS_FILE_CLOSE_REPLY,
	MDS_FILE_FSYNC,
	MDS_FILE_FSYNC_REPLY,
	MDS_FILE_READDIR,
	MDS_FILE_READDIR_REPLY,
	MDS_FILE_STATFS,
	MDS_FILE_STATFS_REPLY,

};

enum {
	DIRECTORY = 1,
	NORMAL_FILE,
};

enum {
	MDS_SUCCESS = 0,
	MDS_ENOENT,
	MDS_EEXIST,
	MDS_ENOTEMPTY,
	MDS_EISDIR,
	MDS_EISFILE,
	MDS_ENAMETOOLONG,
	MDS_EBUSY,
	MDS_ENOTOPEN,
	MDS_EOVERFLOW,
};

enum {
	MDS_O_CREAT = 1,
	MDS_O_RDONLY = 2,
	MDS_O_WRONLY = 2 << 1,
	MDS_O_RDWR = 2 << 2,

};

struct FileOpMKNOD {
	char path[MAX_PATH_LENGTH];
	uint64_t mode;
};

struct FileOpMKDIR {
	char path[MAX_PATH_LENGTH];
	uint64_t mode;
};

struct FileOpUNLINK {
	char path[MAX_PATH_LENGTH];
};

struct FileOpRMDIR {
	char path[MAX_PATH_LENGTH];
};

struct FileOpRENAME {
	char oldpath[MAX_PATH_LENGTH];
	char newpath[MAX_PATH_LENGTH];
};

struct FileOpSTAT {
	char path[MAX_PATH_LENGTH];
};

struct FileOpSTATReply {
	int type;
	union {
		struct Inode fileinfo;
		struct Dir dirinfo;
	};
};


struct FileOpCHMOD {
	char path[MAX_PATH_LENGTH];
	uint64_t mode;
};

struct FileOpCHOWN {
	char path[MAX_PATH_LENGTH];
	uint64_t uid;
	uint64_t gid;
};

struct FileOpOPEN {
	char path[MAX_PATH_LENGTH];
	int flag;
	uint64_t mode;
};

struct FileOpOPENReply {
	struct Inode fileinfo;
};

struct FileOpREAD {
	uint64_t  file_id;
	int64_t offset;
	int64_t size;
};

struct FileOpREADReply {
//	int64_t offset;
//	int64_t size;
	uint32_t count;
	uint32_t data_len;
	struct chunk_id chunks[0];
};

struct FileOpWRITE {
	uint64_t  file_id;
	int64_t offset;
	int64_t size;
};

struct FileOpWRITEReply {
//	int64_t offset;
//	int64_t size;
	uint32_t count;
	uint32_t data_len;
	struct chunk_id chunks[0];
};

struct FileOpTRUNCATE {
	char path[MAX_PATH_LENGTH];
	int64_t size;
};

struct FileOpCLOSE {
	uint64_t  file_id;
};

struct FileOpFSYNC {
	uint64_t  file_id;
};

struct FileOpREADDIR {
	char path[MAX_PATH_LENGTH];
};

struct FileOpREADDIRReply {
	uint32_t count;
	uint32_t data_len;
	struct Dentry dentrys[0];
};


struct statfs {
	int f_type;		/* type of file system */
	int f_bsize;	/* optimal transfer block size */
	int f_blocks;	/* total data blocks in file system */
	int f_bfree;	/* free blocks in fs */
//	int f_bavail;	/* free blocks available to unprivileged user */
	int f_files;	/* total file nodes in file system */
	int f_ffree;	/* free file nodes in fs */
	int f_fsid;		/* file system id */
	int f_namelen;	/* max length of filenames */
};

struct FileOpSTATFS {
	struct statfs fsinfo;
};



#endif
